# 命名空间种类
'''
1.内置名称   比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
2.全局名称   模块中定义的名称，记录了模块的变量，包括函数、类、其它导入的模块、模块级的变量和常量。
3.局部名称   函数中定义的名称，记录了函数的变量，包括函数的参数和局部定义的变量。（类中定义的也是
'''

'''
查找变量:局部的命名空间 -> 全局命名空间 -> 内置命名空间
各命名空间创建顺序：Python 解释器启动 ->创建内建命名空间 -> 加载模块 -> 创建全局命名空间 ->函数被调用 ->创建局部命名空间
各命名空间销毁顺序：函数调用结束 -> 销毁函数对应的局部命名空间 -> Python 虚拟机（解释器）退出 ->销毁全局命名空间 ->销毁内建命名空间
'''

'''
作用域就是一个 Python 程序可以直接访问命名空间的正文区域。

Python 程序中，直接访问一个变量，会从内到外依次访问所有的作用域直到找到，否则会报未定义的错误。
Python 中，程序的变量并不是在哪个位置都可以访问的，访问权限决定于这个变量是在哪里赋值的。
Python 中， 变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称

作用域种类
L（Local）：最内层，包含局部变量，比如一个函数/方法内部。
E（Enclosing）：包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数，一个函数（或类） A 里面又包含了一个函数 B ，那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
G（Global）：当前脚本的最外层，比如当前模块的全局变量。
B（Built-in）： 包含了内建的变量/关键字等，最后被搜索。
'''
global_scope = 0  # 全局作用域

# 定义闭包函数中的局部作用域
def outer():
    o_count = 1  # 闭包函数外的函数中，相对于函数 inner() 来说 作用域非局部
    def inner():
       local_scope = 2  # 局部作用域

# 内建作用域是通过一个名为 builtin 的标准模块来实现的
# import builtins
# print(dir(builtins))

name1 = 'SuSan'
if chr('SuSan'.__eq__(name1)):
    result = 'I am from China'
else:
    result = 'I am from USA'

# print(result)

# 如果将变量定义在函数内部，则外部不能访问
def names():
    name2 = 'SuSan'
# 在程序调用方法内部的变量报错 语法错误
# if('SuSan'.__eq__(name2)):
#     result = 'I am '+name2 +','+'I am from China'
# else:
#     result = 'I am from USA'

# print(result)

'''
全局变量：定义在函数外部拥有全局作用域的变量
局部变量：定义在函数内部拥有局部作用域的变量
'''
# 全局变量和局部变量
total = 0  # 这是一个全局变量
# 函数说明
def sum(arg1, arg2):
    # 返回2个参数的和."
    total = arg1 + arg2  # total在这里是局部变量.
    print("函数内是局部变量 : ", total)
    return total

# 调用sum函数，传入参数的计算结果显示局部变量
# sum(10, 20)
# print("函数外是全局变量 : ", total)

num = 1
def fun1():
# 申明访问全局变量
    global num  # 需要使用 global 关键字声明
# 输出全局变量原始值
    print(num)
#　修改全局变量
    num = 123
    print(num)
# 调用函数
# fun1()
# 输出修改后的全局变量值
# print(num)


# 定义函数
def outer():
# 定义变量
    num = 10
    #　定义嵌套函数
    def inner():
        nonlocal num   # nonlocal关键字声明，使用函数中变量
        # 修改变量值
        num = 100
        print(num)
    inner()
    print(num)
# outer()


'''
两者的功能不同。global 关键字修饰变量后标识该变量是全局变量，对该变量进行修改就是修改全局变量，
而 nonlocal 关键字修饰变量后标识该变量是上一级函数中的局部变量，如果上一级函数中不存在该局部变量，
nonlocal 位置会发生错误（最上层的函数使用 nonlocal 修饰变量必定会报错）。

两者使用的范围不同。global 关键字可以用在任何地方，包括最上层函数中和嵌套函数中，
即使之前未定义该变量，global 修饰后也可以直接使用，而 nonlocal 关键字只能用于嵌套函数中，
并且外层函数中定义了相应的局部变量，否则会发生错误

global 可以在任何地方使用  nonlocal只能在函数中使用
'''